/**
 * Safe Text Replacer - 安全文本替换系统
 * 基于 AI Writer Lite 的实现，为 IntelliMark 提供智能文本替换和验证功能
 */

export interface ReplacementOptions {
  preserveFormatting?: boolean
  preserveCase?: boolean
  preserveIndentation?: boolean
  requireExactMatch?: boolean
  confidenceThreshold?: number
  maxAttempts?: number
  contextWindow?: number
}

export interface ReplacementResult {
  success: boolean
  originalContent: string
  newContent: string
  changes: Array<{
    type: 'replace' | 'insert' | 'delete'
    position: number
    original: string
    replacement: string
    confidence: number
  }>
  confidence: number
  errors: string[]
  warnings: string[]
  metadata: {
    strategy: string
    attempts: number
    processingTime: number
  }
}

export interface TextContext {
  before: string
  after: string
  fullContent: string
  position: number
  selection?: {
    start: number
    end: number
  }
}

export class SafeTextReplacer {
  private defaultOptions: ReplacementOptions = {
    preserveFormatting: true,
    preserveCase: true,
    preserveIndentation: true,
    requireExactMatch: false,
    confidenceThreshold: 0.7,
    maxAttempts: 3,
    contextWindow: 200
  }

  /**
   * 安全替换文本
   */
  public async replace(
    content: string,
    original: string,
    replacement: string,
    options: ReplacementOptions = {}
  ): Promise<ReplacementResult> {
    const startTime = Date.now()
    const opts = { ...this.defaultOptions, ...options }

    const result: ReplacementResult = {
      success: false,
      originalContent: content,
      newContent: content,
      changes: [],
      confidence: 0,
      errors: [],
      warnings: [],
      metadata: {
        strategy: 'unknown',
        attempts: 0,
        processingTime: 0
      }
    }

    try {
      // 验证输入
      this.validateInputs(content, original, replacement, result)

      if (result.errors.length > 0) {
        return result
      }

      // 尝试不同的替换策略
      for (let attempt = 0; attempt < opts.maxAttempts; attempt++) {
        result.metadata.attempts = attempt + 1

        const strategy = this.getReplacementStrategy(attempt, original, replacement, opts)
        result.metadata.strategy = strategy.name

        const attemptResult = await this.attemptReplacement(
          content,
          original,
          replacement,
          strategy,
          opts
        )

        if (attemptResult.confidence >= opts.confidenceThreshold) {
          result.success = true
          result.newContent = attemptResult.content
          result.changes = attemptResult.changes
          result.confidence = attemptResult.confidence
          result.warnings = attemptResult.warnings
          break
        } else {
          result.warnings.push(...attemptResult.warnings)
        }
      }

      // 如果没有成功的替换，记录错误
      if (!result.success) {
        result.errors.push('无法找到合适的替换策略')
      }

    } catch (error) {
      result.errors.push(`替换过程中发生错误: ${error instanceof Error ? error.message : '未知错误'}`)
    }

    result.metadata.processingTime = Date.now() - startTime
    return result
  }

  /**
   * 查找文本位置
   */
  public findTextPositions(
    content: string,
    searchText: string,
    options: {
      caseSensitive?: boolean
      wholeWord?: boolean
      maxResults?: number
    } = {}
  ): Array<{
    start: number
    end: number
    text: string
    context: string
    confidence: number
  }> {
    const opts = {
      caseSensitive: false,
      wholeWord: false,
      maxResults: 10,
      ...options
    }

    const positions: Array<{
      start: number
      end: number
      text: string
      context: string
      confidence: number
    }> = []

    const flags = opts.caseSensitive ? 'g' : 'gi'
    const pattern = opts.wholeWord ? `\\b${this.escapeRegExp(searchText)}\\b` : this.escapeRegExp(searchText)
    const regex = new RegExp(pattern, flags)

    let match
    while ((match = regex.exec(content)) !== null && positions.length < opts.maxResults) {
      const start = match.index
      const end = start + match[0].length
      const contextStart = Math.max(0, start - 50)
      const contextEnd = Math.min(content.length, end + 50)

      positions.push({
        start,
        end,
        text: match[0],
        context: content.substring(contextStart, contextEnd),
        confidence: this.calculateMatchConfidence(match[0], searchText, opts)
      })
    }

    return positions.sort((a, b) => b.confidence - a.confidence)
  }

  /**
   * 获取文本上下文
   */
  public getTextContext(content: string, position: number, windowSize: number = 200): TextContext {
    const before = content.substring(Math.max(0, position - windowSize), position)
    const after = content.substring(position, Math.min(content.length, position + windowSize))

    return {
      before,
      after,
      fullContent: content,
      position
    }
  }

  /**
   * 验证替换结果
   */
  public validateReplacement(
    originalContent: string,
    newContent: string,
    expectedChanges: number
  ): {
    isValid: boolean
    issues: string[]
    suggestions: string[]
  } {
    const issues: string[] = []
    const suggestions: string[] = []

    // 检查内容长度变化
    const lengthChange = Math.abs(newContent.length - originalContent.length)
    if (lengthChange > originalContent.length * 0.5) {
      issues.push('内容长度变化过大，可能替换了错误的部分')
    }

    // 检查是否有意外的格式变化
    const originalLines = originalContent.split('\n')
    const newLines = newContent.split('\n')

    if (Math.abs(newLines.length - originalLines.length) > originalLines.length * 0.3) {
      suggestions.push('行数变化较大，请检查格式是否正确')
    }

    // 检查特殊字符
    const specialChars = /[{}[\]()<>]/
    const originalSpecialCount = (originalContent.match(specialChars) || []).length
    const newSpecialCount = (newContent.match(specialChars) || []).length

    if (originalSpecialCount !== newSpecialCount) {
      suggestions.push('特殊字符数量发生变化，请检查括号匹配')
    }

    return {
      isValid: issues.length === 0,
      issues,
      suggestions
    }
  }

  // 私有方法

  private validateInputs(
    content: string,
    original: string,
    replacement: string,
    result: ReplacementResult
  ): void {
    if (!content) {
      result.errors.push('原内容不能为空')
    }

    if (!original) {
      result.errors.push('要替换的原文不能为空')
    }

    if (!content.includes(original)) {
      result.errors.push('在原文中找不到要替换的文本')
    }

    if (original === replacement) {
      result.errors.push('替换内容与原文相同')
    }
  }

  private async attemptReplacement(
    content: string,
    original: string,
    replacement: string,
    strategy: ReplacementStrategy,
    options: ReplacementOptions
  ): Promise<{
    content: string
    changes: Array<{
      type: 'replace' | 'insert' | 'delete'
      position: number
      original: string
      replacement: string
      confidence: number
    }>
    confidence: number
    warnings: string[]
  }> {
    const changes: Array<{
      type: 'replace' | 'insert' | 'delete'
      position: number
      original: string
      replacement: string
      confidence: number
    }> = []

    const warnings: string[] = []

    try {
      let newContent = content

      switch (strategy.type) {
        case 'exact':
          newContent = this.performExactReplacement(content, original, replacement, changes, options)
          break

        case 'fuzzy':
          newContent = this.performFuzzyReplacement(content, original, replacement, changes, options, warnings)
          break

        case 'contextual':
          newContent = this.performContextualReplacement(content, original, replacement, changes, options, warnings)
          break

        case 'regex':
          newContent = this.performRegexReplacement(content, original, replacement, changes, options, warnings)
          break

        default:
          throw new Error(`未知的替换策略: ${strategy.type}`)
      }

      const confidence = this.calculateOverallConfidence(changes, content, newContent)

      return {
        content: newContent,
        changes,
        confidence,
        warnings
      }

    } catch (error) {
      warnings.push(`替换策略 ${strategy.name} 失败: ${error instanceof Error ? error.message : '未知错误'}`)
      return {
        content,
        changes: [],
        confidence: 0,
        warnings
      }
    }
  }

  private performExactReplacement(
    content: string,
    original: string,
    replacement: string,
    changes: any[],
    options: ReplacementOptions
  ): string {
    let processedReplacement = replacement

    // 保留格式
    if (options.preserveFormatting) {
      processedReplacement = this.preserveFormatting(original, replacement)
    }

    // 保留大小写
    if (options.preserveCase) {
      processedReplacement = this.preserveCase(original, processedReplacement)
    }

    // 执行替换
    let newContent = content
    let position = 0

    while (true) {
      const index = newContent.indexOf(original, position)
      if (index === -1) break

      changes.push({
        type: 'replace',
        position: index,
        original,
        replacement: processedReplacement,
        confidence: 1.0
      })

      newContent = newContent.substring(0, index) + processedReplacement + newContent.substring(index + original.length)
      position = index + processedReplacement.length
    }

    return newContent
  }

  private performFuzzyReplacement(
    content: string,
    original: string,
    replacement: string,
    changes: any[],
    options: ReplacementOptions,
    warnings: string[]
  ): string {
    // 查找相似的文本片段
    const positions = this.findSimilarText(content, original, 0.7)

    if (positions.length === 0) {
      warnings.push('找不到相似的文本片段')
      return content
    }

    // 选择最佳匹配
    const bestMatch = positions[0]
    let processedReplacement = replacement

    if (options.preserveCase) {
      processedReplacement = this.preserveCase(bestMatch.text, processedReplacement)
    }

    changes.push({
      type: 'replace',
      position: bestMatch.start,
      original: bestMatch.text,
      replacement: processedReplacement,
      confidence: bestMatch.confidence
    })

    return content.substring(0, bestMatch.start) + processedReplacement + content.substring(bestMatch.end)
  }

  private performContextualReplacement(
    content: string,
    original: string,
    replacement: string,
    changes: any[],
    options: ReplacementOptions,
    warnings: string[]
  ): string {
    // 基于上下文的智能替换
    const positions = this.findContextualMatches(content, original, options.contextWindow || 200)

    if (positions.length === 0) {
      warnings.push('找不到合适的上下文匹配')
      return content
    }

    const bestMatch = positions[0]
    let processedReplacement = replacement

    if (options.preserveFormatting) {
      processedReplacement = this.preserveFormatting(bestMatch.text, processedReplacement)
    }

    if (options.preserveIndentation) {
      processedReplacement = this.preserveIndentation(bestMatch.text, processedReplacement)
    }

    changes.push({
      type: 'replace',
      position: bestMatch.start,
      original: bestMatch.text,
      replacement: processedReplacement,
      confidence: bestMatch.confidence
    })

    return content.substring(0, bestMatch.start) + processedReplacement + content.substring(bestMatch.end)
  }

  private performRegexReplacement(
    content: string,
    original: string,
    replacement: string,
    changes: any[],
    options: ReplacementOptions,
    warnings: string[]
  ): string {
    try {
      const pattern = new RegExp(this.escapeRegExp(original), 'g')
      let newContent = content
      let match

      while ((match = pattern.exec(content)) !== null) {
        changes.push({
          type: 'replace',
          position: match.index,
          original: match[0],
          replacement,
          confidence: 0.8
        })

        newContent = newContent.replace(match[0], replacement)
      }

      return newContent
    } catch (error) {
      warnings.push(`正则表达式替换失败: ${error instanceof Error ? error.message : '未知错误'}`)
      return content
    }
  }

  private findSimilarText(content: string, target: string, threshold: number): Array<{
    start: number
    end: number
    text: string
    confidence: number
  }> {
    const results: Array<{
      start: number
      end: number
      text: string
      confidence: number
    }> = []

    const words = target.split(/\s+/)
    const windowSize = Math.max(50, target.length * 2)

    for (let i = 0; i < content.length - windowSize; i += 10) {
      const window = content.substring(i, i + windowSize)
      const similarity = this.calculateSimilarity(target, window)

      if (similarity >= threshold) {
        // 提取最佳匹配子串
        const bestMatch = this.extractBestMatch(window, target)
        results.push({
          start: i + bestMatch.offset,
          end: i + bestMatch.offset + bestMatch.text.length,
          text: bestMatch.text,
          confidence: similarity
        })
      }
    }

    return results.sort((a, b) => b.confidence - a.confidence).slice(0, 3)
  }

  private findContextualMatches(content: string, target: string, windowSize: number): Array<{
    start: number
    end: number
    text: string
    confidence: number
  }> {
    const results: Array<{
      start: number
      end: number
      text: string
      confidence: number
    }> = []

    // 寻找在相似上下文中的匹配
    const targetWords = target.toLowerCase().split(/\s+/)

    for (let i = 0; i < content.length - target.length; i++) {
      const contextStart = Math.max(0, i - windowSize)
      const contextEnd = Math.min(content.length, i + target.length + windowSize)
      const context = content.substring(contextStart, contextEnd)

      // 检查上下文相似性
      const contextScore = this.calculateContextSimilarity(target, context)
      const textScore = this.calculateSimilarity(target, content.substring(i, i + target.length))

      const overallScore = (contextScore + textScore) / 2

      if (overallScore > 0.6) {
        results.push({
          start: i,
          end: i + target.length,
          text: content.substring(i, i + target.length),
          confidence: overallScore
        })
      }
    }

    return results.sort((a, b) => b.confidence - a.confidence)
  }

  private extractBestMatch(window: string, target: string): {
    text: string
    offset: number
  } {
    const targetWords = target.toLowerCase().split(/\s+/)
    const windowWords = window.toLowerCase().split(/\s+/)

    let bestMatch = { text: '', offset: 0 }
    let bestScore = 0

    for (let i = 0; i <= windowWords.length - targetWords.length; i++) {
      const candidateWords = windowWords.slice(i, i + targetWords.length)
      const candidate = candidateWords.join(' ')
      const score = this.calculateSimilarity(target.toLowerCase(), candidate)

      if (score > bestScore) {
        bestScore = score
        // 找到原始文本中的实际位置
        const originalOffset = window.toLowerCase().indexOf(candidate)
        if (originalOffset !== -1) {
          bestMatch = {
            text: window.substring(originalOffset, originalOffset + candidate.length),
            offset: originalOffset
          }
        }
      }
    }

    return bestMatch
  }

  private calculateSimilarity(str1: string, str2: string): number {
    // 使用编辑距离计算相似性
    const longer = str1.length > str2.length ? str1 : str2
    const shorter = str1.length > str2.length ? str2 : str1

    if (longer.length === 0) return 1.0

    const editDistance = this.levenshteinDistance(longer, shorter)
    return (longer.length - editDistance) / longer.length
  }

  private calculateContextSimilarity(target: string, context: string): number {
    // 计算上下文相似性
    const targetWords = new Set(target.toLowerCase().split(/\s+/))
    const contextWords = context.toLowerCase().split(/\s+/)

    const intersection = Array.from(targetWords).filter(word => contextWords.includes(word))
    const union = new Set([...targetWords, ...contextWords])

    return intersection.length / union.size
  }

  private levenshteinDistance(str1: string, str2: string): number {
    const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null))

    for (let i = 0; i <= str1.length; i++) matrix[0][i] = i
    for (let j = 0; j <= str2.length; j++) matrix[j][0] = j

    for (let j = 1; j <= str2.length; j++) {
      for (let i = 1; i <= str1.length; i++) {
        const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1
        matrix[j][i] = Math.min(
          matrix[j][i - 1] + 1,
          matrix[j - 1][i] + 1,
          matrix[j - 1][i - 1] + indicator
        )
      }
    }

    return matrix[str2.length][str1.length]
  }

  private calculateMatchConfidence(match: string, target: string, options: any): number {
    let confidence = 1.0

    if (!options.caseSensitive && match.toLowerCase() !== target.toLowerCase()) {
      confidence -= 0.3
    }

    if (match.length !== target.length) {
      confidence -= 0.2
    }

    return Math.max(0, confidence)
  }

  private calculateOverallConfidence(
    changes: any[],
    originalContent: string,
    newContent: string
  ): number {
    if (changes.length === 0) return 0

    const avgChangeConfidence = changes.reduce((sum, change) => sum + change.confidence, 0) / changes.length

    // 根据整体变化调整置信度
    const lengthChange = Math.abs(newContent.length - originalContent.length)
    const lengthChangeRatio = lengthChange / originalContent.length
    const lengthPenalty = Math.min(0.3, lengthChangeRatio * 0.5)

    return Math.max(0, avgChangeConfidence - lengthPenalty)
  }

  private preserveFormatting(original: string, replacement: string): string {
    // 简单的格式保留逻辑
    const originalPrefix = original.match(/^[\s\t]*/)?.[0] || ''
    const originalSuffix = original.match(/[\s\t]*$/)?.[0] || ''

    return originalPrefix + replacement.trim() + originalSuffix
  }

  private preserveCase(original: string, replacement: string): string {
    if (original.toUpperCase() === original) {
      return replacement.toUpperCase()
    } else if (original.toLowerCase() === original) {
      return replacement.toLowerCase()
    } else if (original[0] === original[0].toUpperCase()) {
      return replacement[0].toUpperCase() + replacement.slice(1).toLowerCase()
    }

    return replacement
  }

  private preserveIndentation(original: string, replacement: string): string {
    const indent = original.match(/^[\s\t]*/)?.[0] || ''
    return indent + replacement
  }

  private escapeRegExp(string: string): string {
    return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
  }

  private getReplacementStrategy(
    attempt: number,
    original: string,
    replacement: string,
    options: ReplacementOptions
  ): ReplacementStrategy {
    switch (attempt) {
      case 0:
        return { name: 'exact', type: 'exact' }
      case 1:
        return { name: 'contextual', type: 'contextual' }
      case 2:
        return { name: 'fuzzy', type: 'fuzzy' }
      default:
        return { name: 'regex', type: 'regex' }
    }
  }
}

interface ReplacementStrategy {
  name: string
  type: 'exact' | 'fuzzy' | 'contextual' | 'regex'
}

// 导出单例实例
let safeTextReplacerInstance: SafeTextReplacer | null = null

export function getSafeTextReplacer(): SafeTextReplacer {
  if (!safeTextReplacerInstance) {
    safeTextReplacerInstance = new SafeTextReplacer()
  }
  return safeTextReplacerInstance
}